/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.formserver.vmmanager.generatacmpcode;


import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.formserver.viewmodel.action.ActionParamInfo;
import com.inspur.edp.formserver.viewmodel.action.IViewModelParameter;
import com.inspur.edp.formserver.viewmodel.action.MappedCdpAction;
import com.inspur.edp.formserver.viewmodel.action.viewmodelbase.ViewModelParameter;
import com.inspur.edp.formserver.viewmodel.action.viewmodelbase.ViewModelVoidReturnValue;
import com.inspur.edp.formserver.viewmodel.common.VMCollectionParameterType;
import com.inspur.edp.formserver.viewmodel.common.VMParameterType;
import com.inspur.edp.formserver.viewmodel.exception.ViewModelException;
import com.inspur.edp.formserver.viewmodel.util.ViewModelUtils;
import com.inspur.edp.formserver.vmmanager.exception.VoManagerErrorCodes;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;

public abstract class JavaBaseActionGenerator extends JavaBaseCompCodeGenerator {

    ///#region 字段和属性
    private MappedCdpAction vmAction;
    private ArrayList<String> usingList;
    private LinkedHashMap<String, ParameterInfo> parameters;
    private ArrayList<Class> allGenericParamType;
    protected String ReturnTypeName = "VoidActionResult";
    protected String errorCode = "VmBaseActionGenerator";

    ///#endregion
    ///#region 构造与初始化
    public JavaBaseActionGenerator(ActionParamInfo info, GspViewModel vm, MappedCdpAction vmAction, String nameSpace, String path) {
        super(info, vm, vmAction, nameSpace, path);
        this.vmAction = vmAction;
        if (this.vmAction == null) {
            throw new ViewModelException(VoManagerErrorCodes.GSP_VIEWOBJECT_MANAGER_0019, null);
        }
        this.usingList = new ArrayList<>();
        this.allGenericParamType = new ArrayList<>();


        ///#region ReturnValue
        if (this.vmAction.getReturnValue() != null && !(this.vmAction.getReturnValue() instanceof ViewModelVoidReturnValue)) {
            getParameterUsing(this.vmAction.getReturnValue());
            ReturnTypeName = GetParameterTypeName(this.vmAction.getReturnValue());
        }

        ///#endregion


        ///#region Parameters
        if (this.vmAction.getParameterCollection() == null || this.vmAction.getParameterCollection().getCount() < 1) {
            return;
        }
        parameters = new LinkedHashMap<>();

        for (Object actionParameter : this.vmAction.getParameterCollection()) {
            getParameterUsing((IViewModelParameter) actionParameter);
            if (parameters.containsKey(((IViewModelParameter) actionParameter).getParamCode())) {
                throw new ViewModelException(VoManagerErrorCodes.GSP_VIEWOBJECT_MANAGER_0020, null, this.vmAction.getCode(), this.vmAction.getName(), ((IViewModelParameter) actionParameter).getParamCode());
            }
            parameters.put(((IViewModelParameter) actionParameter).getParamCode(), buildParameterInfo(
                    (IViewModelParameter) actionParameter));


        }

        ///#endregion
    }

    private void getParameterUsing(IViewModelParameter param) {
        if (param.getCollectionParameterType() == VMCollectionParameterType.List) {
            addUsing(JavaCompCodeNames.ArrayListNameSpace);
        }
        if (param.getParameterType() == VMParameterType.DateTime) {
            addUsing(JavaCompCodeNames.DateNameSpace);
        }
        if (param.getParameterType() == VMParameterType.Decimal) {
            addUsing(JavaCompCodeNames.BigDecimalNameSpace);
        }
        if (param.getParameterType() == VMParameterType.Custom) {
            addUsing(param.getClassName());
        }
        if (param.getParameterType() == VMParameterType.Stream) {
            addUsing(JavaCompCodeNames.ResponeseNameSpace);
        }
    }

    private String GetParameterTypeName(IViewModelParameter param) {
        switch (param.getCollectionParameterType()) {
            case None:
                return GetNoneCollectionParaTypeName(param);
            case List:
                return GetListParaTypeName(param);
            case Array:
                return GetArrayParaTypeName(param);
            default:
                throw new ViewModelException(VoManagerErrorCodes.GSP_VIEWOBJECT_MANAGER_0021, null,
                        param.getParamCode(), param.getParamName(), param.getCollectionParameterType().toString());
        }
    }

    private String GetArrayParaTypeName(IViewModelParameter param) {
        switch (param.getParameterType()) {
            case String:
                return "String[]";
            case Boolean:
                return "Boolean[]";
            case DateTime:
                return "Date[]";
            case Decimal:
                return "BigDecimal[]";
            case Double:
                return "Double[]";
            case Int32:
                return "Integer[]";
            case Object:
                return "Object[]";
            case Stream:
                return "Response[]";
            default:
                handleJavaInfo(param);
                if (ViewModelUtils.checkNull(param.getClassName())) {
                    throw new ViewModelException(VoManagerErrorCodes.GSP_VIEWOBJECT_MANAGER_0022,
                            null, param.getParamCode(), param.getParamName());
                }
                int index = param.getClassName().lastIndexOf(".");
                return param.getClassName().substring(index + 1, param.getClassName().length()) + "[]";
        }

    }

    private String GetListParaTypeName(IViewModelParameter param) {
        switch (param.getParameterType()) {
            case String:
                return "ArrayList<String>";
            case Boolean:
                return "ArrayList<Boolean>";
            case DateTime:
                return "ArrayList<Date>";
            case Decimal:
                return "ArrayList<BigDecimal>";
            case Double:
                return "ArrayList<Double>";
            case Int32:
                return "ArrayList<Integer>";
            case Object:
                return "ArrayList<Object>";
            case Stream:
                return "ArrayList<Response>";
            default:
                handleJavaInfo(param);
                if (ViewModelUtils.checkNull(param.getClassName())) {
                    throw new ViewModelException(VoManagerErrorCodes.GSP_VIEWOBJECT_MANAGER_0022,
                            null, param.getParamCode(), param.getParamName());
                }
                int index = param.getClassName().lastIndexOf(".");
                return "ArrayList<" + param.getClassName().substring(index + 1, param.getClassName().length()) + ">";
        }
    }

    private String GetNoneCollectionParaTypeName(IViewModelParameter param) {
        switch (param.getParameterType()) {
            case String:
                return "String";
            case Boolean:
                return "Boolean";
            case DateTime:
                return "Date";
            case Decimal:
                return "BigDecimal";
            case Double:
                return "Double";
            case Int32:
                return "Integer";
            case Object:
                return "Object";
            case Stream:
                return "Response";
            default:
                handleJavaInfo(param);
                if (ViewModelUtils.checkNull(param.getClassName())) {
                    throw new ViewModelException(VoManagerErrorCodes.GSP_VIEWOBJECT_MANAGER_0022,
                            null, param.getParamCode(), param.getParamName());
                }
                int index = param.getClassName().lastIndexOf(".");
                return param.getClassName().substring(index + 1, param.getClassName().length());
//				if (!IsGeneric(param))
//				{
//					return param.getJavaClassName().substring(index + 1, index + 1 + param.getJavaClassName().length() - index - 1);
//				}
//				else
//				{
//					String result = GetGenericExpress(allGenericParamType.get(0));
//					allGenericParamType.clear();
//					return result;
//				}

        }
    }

    private String getParameterMode(IViewModelParameter param) {
        switch (param.getMode()) {
            case OUT:
                return "out";
            //TODO 待确认
            case INOUT:
                return "ref";
            default:
                return "";
        }

    }

    private ParameterInfo buildParameterInfo(IViewModelParameter param) {
        String typeName = GetParameterTypeName(param);
        String paramMode = getParameterMode(param);
        ParameterInfo tempVar = new ParameterInfo();
        tempVar.setParamName(param.getParamCode());
        tempVar.setParamType(typeName);
        tempVar.setParameterMode(paramMode);
        return tempVar;
    }

    @Override
    protected void generateExtendUsing(StringBuilder result) {
        result.append(getUsingStr(JavaCompCodeNames.FormServerSpiNameSpace));
        result.append(getUsingStr(JavaCompCodeNames.BefApiActionNameSpace));

        //参数列表
        if (usingList == null || usingList.size() < 1) {
            return;
        }
        for (String usingName : usingList) {
            result.append(getUsingStr(usingName));
        }
    }

    protected boolean hasCustomConstructorParams() {
        if (parameters == null || parameters.size() < 1) {
            return false;
        }
        return true;
    }

    protected void generateConstructorParams(StringBuilder result) {
        for (int i = 0; i < parameters.size(); i++) {

            String parameterKey = (String) parameters.keySet().toArray()[i];

            ParameterInfo parameterValue = parameters.get(parameterKey);

            if (!ViewModelUtils.checkNull(parameterValue.getParameterMode())) {
                result.append(parameterValue.getParameterMode()).append(" ");
            }
            result.append(parameterValue.getParamType()).append(" ").append(parameterKey);
            if (i < parameters.size() - 1) {
                result.append(",");
            }
        }
    }

    protected void generateConstructorContent(StringBuilder result) {
        if (parameters == null || parameters.size() < 1) {
            return;
        }

        for (Map.Entry<String, ParameterInfo> parameter : parameters.entrySet()) {
            result.append(getNewLine()).append(getIndentationStr()).append(getIndentationStr()).append("this.").append(parameter.getKey()).append(" = ").append(parameter.getKey()).append(";");

        }
    }

    ///#endregion


    ///#region Field
    @Override
    protected void generateField(StringBuilder result) {

        if (parameters == null || parameters.size() < 1) {
            return;
        }

        for (Map.Entry<String, ParameterInfo> parameter : parameters.entrySet()) {
            result.append(getNewLine()).append(getIndentationStr()).append(JavaCompCodeNames.KeywordPrivate).append(" ").append(parameter.getValue().getParamType()).append(" ").append(parameter.getKey()).append(";");
        }
    }

    ///#endregion
//TODO 后续确认
    private boolean IsGeneric(IViewModelParameter param) {
        return false;
//		try
//		{
//
//			var psn = Assembly.Load(param.getAssembly());
//			Class type = psn.GetType(param.getJavaClassName());
//			return type.IsGenericType;
//		}
//		catch (Exception e)
//		{
//			//如果libs目录下如果未加载到程序集，默认其不是泛型类型
//			return false;
//		}
    }

    //TODO 后续确认
    //把泛型参数类型涉及到的所有类型得到并存在List集合中
    private void getAllGenericParameterType(Class type) {
//		if (allGenericParamType.isEmpty())
//		{
//			allGenericParamType.add(type);
//		}
//		Class[] allType = type.getGenericArguments();
//
//		for (Class t : allType)
//		{
//			allGenericParamType.add(t);
//			if (t.IsGenericType)
//			{
//				getAllGenericParameterType(t);
//			}
//		}

    }

    private void addUsing(String usingName) {
        if (ViewModelUtils.checkNull(usingName)) {
            throw new ViewModelException(VoManagerErrorCodes.GSP_VIEWOBJECT_MANAGER_0023, null);
        }
        if (!ViewModelUtils.checkNull(usingName) && !usingList.contains(usingName)) {
            usingList.add(usingName);
        }
    }

    private String getClassName(Class type) {
        if (Integer.class == type) {
            return "Integer";
        }
        if (String.class == type) {
            return "String";
        }
        if (Boolean.class == type) {
            return "Boolean";
        }
        if (Date.class == type) {
            return "Date";
        }
        if (java.math.BigDecimal.class == type) {
            return "BigDecimal";
        }
        if (Double.class == type) {
            return "BigDecimal";
        }
        if (Object.class == type) {
            return "Object";
        }

        String fullClassName = type.toString().split("[`]", -1)[0];
        String[] content = fullClassName.split("[.]", -1);
        return content[content.length - 1];


    }

    //TODO 后续确认
    private String getGenericExpress(Class type) {
        return "";
    }

    private void handleJavaInfo(IViewModelParameter para) {
        if (ViewModelUtils.checkNull(para.getClassName()) && !ViewModelUtils.checkNull(((ViewModelParameter) para).getDotnetClassName())) {
            //仅平台提供包，自动转Inspur.Gsp为com.inspur.edp
            if (((ViewModelParameter) para).getDotnetClassName().startsWith("Inspur.Gsp.")) {
                para.setClassName(handleJavaClassName(((ViewModelParameter) para).getDotnetClassName()));
            }
        }
    }

    private String handleJavaClassName(String source) {
        if (ViewModelUtils.checkNull(source)) {
            return source;
        }
        String result = "";
        String[] list = source.split("[.]", -1);
        for (int i = 0; i < list.length; i++) {
            String lowerCase = list[i].toLowerCase(Locale.ROOT);
            if (i == 0 && lowerCase.equals("inspur")) {
                result = String.format("%1$s%2$s", result, "com.inspur");
                continue;
            }
            if (i == list.length - 1) {
                // 类名不需要转换为小写
                result = String.format("%1$s%2$s%3$s", result, ".", list[i]);
                continue;
            }
            result = String.format("%1$s%2$s%3$s", result, ".", lowerCase);
        }
        return result;
    }
}
